package cn.ljn.basic.service.impl;


import cn.ljn.basic.constant.BaseConstants;
import cn.ljn.basic.dto.EmailDto;
import cn.ljn.basic.dto.PhoneCodeDto;
import cn.ljn.basic.dto.VerifyCodeDto;
import cn.ljn.basic.service.VerifyCodeService;
import cn.ljn.basic.util.BusinessException;
import cn.ljn.basic.util.VerifyCodeUtils;
import cn.ljn.user.domain.Logininfo;
import cn.ljn.user.domain.User;
import cn.ljn.user.mapper.LogininfoMapper;
import cn.ljn.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements VerifyCodeService {
            @Autowired
           private RedisTemplate redisTemplate;

            @Autowired
            private LogininfoMapper logininfoMapper;
            @Autowired
            private UserMapper userMapper;
            

    @Override
    public String imageCode(String key) throws IOException {
        // 校验传递的key是否为空
        if (StringUtils.isEmpty(key)) {
            throw new BusinessException("请传递参数");
        }
        // 调用字符串工具类方法获取四位随机字符串（验证码）
        String code = VerifyCodeUtils.generateVerifyCode(1);
        // 将随机字符串设置到redis中，key就是传递的key值
        redisTemplate.opsForValue().set(key, code, 3, TimeUnit.MINUTES);
        // 将code值生成图形并编码成Base64
        String baseStr = VerifyCodeUtils.VerifyCode(100, 35, code);
        return baseStr;
    }
    // 发送短信验证码
    @Override
    public void smsCode(VerifyCodeDto verifyCodeDto) {
        if (verifyCodeDto.getType().equals("binder")) {
            // 发送短信
            this.sendSms(BaseConstants.BINDER_REDIS_KEY,verifyCodeDto);
        } else if (verifyCodeDto.getType().equals("register")) {
            // 参数验证
            this.imageVerify(verifyCodeDto);
            // 发送短信
            this.sendSms(BaseConstants.PHONE_REDIS_KEY,verifyCodeDto);
        }


    }
    // 手机号注册
    @Override
    public void phoneRegister(PhoneCodeDto dto) {
        // 参数校验
        // 1.判断手机验证码是否正确 业务键+手机号获取值
        String phoneCode = (String) redisTemplate.opsForValue().get(String.format(BaseConstants.PHONE_REDIS_KEY, dto.getPhone()));
        if (StringUtils.isBlank(phoneCode) || !phoneCode.equals(dto.getSmsCode())) {
            throw new BusinessException("手机验证码不一致");
        }

        // 2.判断两次密码是否正确
        if (!dto.getPassword().equals(dto.getPasswordRepeat())) {
            throw new BusinessException("密码不一致");
        }

        // 3.判断手机号是否存在
        User user = userMapper.findByPhone(dto.getPhone());
        if (user != null) {
            throw new BusinessException("用户已存在");
        }

        // 5.添加进数据库
        // 先获取user对象
        user = dto.getUser();
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user, logininfo);
        logininfo.setType(1);
        logininfo.setDisable(true);
        logininfoMapper.add(logininfo);
        user.setLogininfoId(logininfo.getId());
        userMapper.add(user);

    }
    // 邮箱注册
    @Override
    public void emailRegister(EmailDto dto) {
        // 校验参数
        // QQ邮件正则格式
//        String regex6 = "[1-9]\\d{7,10}@qq\\.com";
        // 1.判断邮箱是否为空
        if (dto.getEmail() == null) {
            throw new BusinessException("邮件为空");
        }
        // 2.判断图片验证码是否错误
        String imageCode = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        System.out.println(imageCode);
        if (dto.getImageCodeValue() == null || !imageCode.equalsIgnoreCase(dto.getImageCodeValue())) {
            throw new BusinessException("图形验证码错误");
        }
        // 3.判断邮件是否存在
        User email = userMapper.findByEmail(dto.getEmail());
        if (email != null) {
            throw new BusinessException("邮件已存在");
        }
        // 4.添加进数据库
        // 先获取user对象
        User user = dto.getUser();
        // 再获取logininfo对象
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user, logininfo);
        logininfo.setType(1);
        logininfo.setDisable(true);
        logininfoMapper.add(logininfo);
        user.setLogininfoId(logininfo.getId());
        userMapper.add(user);

    }

    private void imageVerify(VerifyCodeDto verifyCodeDto) {
        // 1.校验参数
        // 2.判断图形验证码是否存在或是否正确
        // 获取图形验证码进行判断
        String imageCodeValue = (String) redisTemplate.opsForValue().get(verifyCodeDto.getImageCodeKey());
        if (StringUtils.isBlank(imageCodeValue) || !imageCodeValue.equalsIgnoreCase(verifyCodeDto.getImageCodeValue())) {
            throw new BusinessException("图形验证码错误");
        }
        // 3.判断手机号是否存在（用户是否已注册）
        // 根据手机号获取用户信息 判断是否存在
        User user = userMapper.findByPhone(verifyCodeDto.getPhone());
        if (user != null) {
            throw new BusinessException("用户已存在");
        }
    }
    private void sendSms(String redisKey, VerifyCodeDto verifyCodeDto) {
        // 4.判断两次发送时间是否大于60s
        // 获取过期时间 redisTemplate.getExpire: redisTemplate获取到设置的过期时间
        Long expire = redisTemplate.getExpire(String.format(redisKey, verifyCodeDto.getPhone()));
        System.out.println(expire);
        // 根据过期时间大于120s判断是否可以发送第二次 默认一分钟才发送一次
        if (expire != null && expire > (BaseConstants.PHONE_REGISTER_REDIS_TTL - 1) * 60L) {
            throw new BusinessException("请一分钟后获取");
        }
        // 5.是否需要重置验证码
        // 获取验证码
        String smsImageCodeValue = (String)redisTemplate.opsForValue().get(String.format(redisKey, verifyCodeDto.getPhone()));
        // 验证码不存在 代表已经过期或没有 重新生成
        if (StringUtils.isBlank(smsImageCodeValue)) {
            smsImageCodeValue = VerifyCodeUtils.generateVerifyCode(4);
        }
        log.info("手机验证码为：{}", smsImageCodeValue);
        // 6.将手机验证码存在redis中
        redisTemplate.opsForValue().set(
                String.format(redisKey, verifyCodeDto.getPhone())// RedisKey
                , smsImageCodeValue // RedisValue 验证码
                , BaseConstants.PHONE_REGISTER_REDIS_TTL // 过期时间
                , TimeUnit.MINUTES);

        // 7.发送短信
//        SmsUtils.sendSms("18280317181","5269");
    }

}
